package com.simpleconfigwizard.rnmodule;

import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.realtek.simpleconfiglib.SCLibrary;
import com.rtk.simpleconfig_wizard.SCCtlOps;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import static android.content.Context.WIFI_SERVICE;

/**
 * Created by xy on 16/10/20.
 */

public class SimpleConfigModule extends ReactContextBaseJavaModule
{
    private SCLibrary SCLib = new SCLibrary();

    private boolean TimesupFlag_cfg = false;

    private Callback successCallback = null;

    private Callback errorCallback = null;

    static
    {
        System.loadLibrary("simpleconfiglib");
    }

    public SimpleConfigModule(ReactApplicationContext reactContext)
    {
        super(reactContext);
    }

    @Override
    public String getName()
    {
        return "SimpleConfig";
    }

    @ReactMethod
    public void configDevice(final String ssid, final String password, final int configTimeout,
                             final Callback successCallback,
                             final Callback errorCallback)
    {
        new Thread()
        {
            public void run()
            {
                SimpleConfigModule.this.successCallback = successCallback;
                SimpleConfigModule.this.errorCallback = errorCallback;
                Configure_action(ssid, password, configTimeout);
            }
        }.start();
    }

    //<func>
    private void Configure_action(String ConnectedSSID, String ConnectedPasswd, int configTimeout)
    {
        int stepOneTimeout = configTimeout / 4;
        String PINSet = "";
        String pinCodeText = "";
        String defaultPINcode = "57289961";
        int connect_count = 200;

        //check wifi connected
        if (ConnectedSSID == null) {
            return;
        }

        //simple config lib init
        SCLib.rtk_sc_init();

        MsgHandlerThread ht = new MsgHandlerThread();
        ht.start();
        SCLib.TreadMsgHandler = new Handler(ht.getLooper(), ht);
        //wifi manager init
        SCLib.WifiInit(getReactApplicationContext());

        //get wifi ip
        int wifiIP = SCLib.WifiGetIpInt();
        while(connect_count>0 && wifiIP==0){
            wifiIP = SCLib.WifiGetIpInt();
            connect_count--;
        }
        if(wifiIP == 0 && errorCallback != null){
            errorCallback.invoke("Allocating IP, please wait a moment");
            return;
        }

        SCLib.rtk_sc_reset();
        if(PINSet == null){
            SCLib.rtk_sc_set_default_pin(defaultPINcode);
        }else if(PINSet.length()>0){
            SCLib.rtk_sc_set_default_pin(defaultPINcode);
        }

        if(pinCodeText.length()>0){
            SCLib.rtk_sc_set_pin(pinCodeText);
        }
        else
            SCLib.rtk_sc_set_pin(PINSet);

        SCLib.rtk_sc_set_ssid(ConnectedSSID);

        if(ConnectedPasswd != null && !ConnectedPasswd.isEmpty()) {
            SCLib.rtk_sc_set_password(ConnectedPasswd);
        }

        TimesupFlag_cfg = false;

        SCLib.rtk_sc_set_ip(wifiIP);
        SCLib.rtk_sc_build_profile();

        SCLibrary.ProfileSendTimeMillis = configTimeout;

        //==================== 1 ========================= 30s
		/* Time interval(ms) between sending two profiles. */
        SCLibrary.ProfileSendTimeIntervalMs = 50; //50ms

		/* Time interval(ms) between sending two packets. */
        SCLibrary.PacketSendTimeIntervalMs  = 0; //0ms

		/* Each packet sending counts. */
        SCLibrary.EachPacketSendCounts = 1;

        //exception action
        exception_action();

        SCLib.rtk_sc_start();
        int watchCount = 0;
        try {
            do{
                Thread.sleep(1000);
                watchCount+=1000;
            }while(TimesupFlag_cfg==false && watchCount<stepOneTimeout);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //==================== 2 =========================
        if(TimesupFlag_cfg==false)
        {
            int count = 0;
            /* Time interval(ms) between sending two profiles. */
            SCLibrary.ProfileSendTimeIntervalMs = 200; //200ms

            /* Time interval(ms) between sending two packets. */
            SCLibrary.PacketSendTimeIntervalMs = 10; //10ms

            /* Each packet sending counts. */
            SCLibrary.EachPacketSendCounts = 1;

            try
            {
                do
                {
                    Thread.sleep(1000);
                    count++;
                    if ((((configTimeout - stepOneTimeout) / 1000) - count) < 0)
                        break;
                } while (TimesupFlag_cfg == false);

            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }

            TimesupFlag_cfg = true;

            SCLib.rtk_sc_stop();
//            Message msg = new Message();
//            msg.what = ~
//            SCLib.TreadMsgHandler.sendMessage(msg);
        }
    }

    private void exception_action()
    {
        if(Build.MANUFACTURER.equalsIgnoreCase("Samsung")){
            if (Build.MODEL.equalsIgnoreCase("G9008")){ //Samsung Galaxy S5 SM-G9008
                SCLibrary.PacketSendTimeIntervalMs  = 10;
            }else if(Build.MODEL.contains("SM-G9208")){ //samsun Galaxy S6
                SCLibrary.PacketSendTimeIntervalMs  = 10;
            }else if(Build.MODEL.contains("N900")){ //samsun Galaxy note 3
                SCLibrary.PacketSendTimeIntervalMs  = 5;
            }else if(Build.MODEL.contains("SM-N910U")){ //samsun Galaxy note 4
                SCLibrary.PacketSendTimeIntervalMs  = 5;
            }

        }else if(Build.MANUFACTURER.equalsIgnoreCase("Xiaomi")){//for MI
            if (Build.MODEL.equalsIgnoreCase("MI 4W")){
                SCLibrary.PacketSendTimeIntervalMs  = 5;	//MI 4
            }
        }else if(Build.MANUFACTURER.equalsIgnoreCase("Sony")){//for Sony
            if (Build.MODEL.indexOf("Xperia")>0){
                SCLibrary.PacketSendTimeIntervalMs  = 5;	//Z3
            }
        }

        //check link rate
        WifiManager wifi_service = (WifiManager) getReactApplicationContext().getSystemService(WIFI_SERVICE);
        WifiInfo wifiinfo = wifi_service.getConnectionInfo();
        if( wifiinfo.getLinkSpeed() > 78 ){//MCS8 , 20MHZ , NOSGI
            SCLibrary.ProfileSendTimeIntervalMs = 100; //50ms
            SCLibrary.PacketSendTimeIntervalMs  = 15;
        }
    }

    //<func>
    private synchronized void showConfiguredList()
    {
        SCLib.rtk_sc_stop();

        final List<HashMap<String, Object>> InfoList = new ArrayList<HashMap<String, Object>>();

        final int itemNum = SCLib.rtk_sc_get_connected_sta_num();
        SCLib.rtk_sc_get_connected_sta_info(InfoList);

        //input data
        if(itemNum>0){
            String name;
            String mac;
            String ip;
            WritableArray array = new WritableNativeArray();
            for (int i=0; i<itemNum; i++) {

                if(InfoList.get(i).get("Name")==null)
                {
                    name = (String) InfoList.get(i).get("MAC");
                    name = name.toUpperCase();
                }
                else
                {
                    name = (String) InfoList.get(i).get("Name");
                }

                mac = (String)InfoList.get(i).get("MAC");
                mac = mac.toUpperCase();
                ip = (String)InfoList.get(i).get("IP");
                Log.d("found device: ", mac + ", " + name + ", " + ip);

                WritableMap map = new WritableNativeMap();
                map.putString("Name", name);
                map.putString("MAC", mac);
                map.putString("IP", ip);

                if(mac.equals("00:00:00:00:00:00") || ip == null || ip.isEmpty())
                {
                    continue;
                }
                array.pushMap(map);
            }

            if(successCallback != null)
            {
                successCallback.invoke(array);
                successCallback = null;
                errorCallback = null;
            }
        }
        else if(errorCallback != null)
        {
            errorCallback.invoke("No device found.");
            successCallback = null;
            errorCallback = null;
        }
    }

    private class MsgHandlerThread extends HandlerThread implements android.os.Handler.Callback {

        public MsgHandlerThread() {
            super("MsgHandlerThread");
        }

        @Override
        public boolean handleMessage(Message msg){
            switch(msg.what) {
                case ~SCCtlOps.Flag.CfgSuccessACK://Config Timeout
                    SCLib.rtk_sc_stop();
                    showConfiguredList();

                    break;
                case SCCtlOps.Flag.CfgSuccessACK: //Not Showable
                    SCLib.rtk_sc_stop();

                    TimesupFlag_cfg = true;
                    showConfiguredList();

                    break;

                default:
                    break;
            }


            return true;
        }

    }
}
